#pragma once
#include <atomic>
#include <memory>
#include <deque>
#include "LxPThreadAux.h"

#ifndef WAIT_TIMEOUT
#define WAIT_TIMEOUT 0x00000102
#endif
#ifndef WAIT_FAILED
#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
#endif
#ifndef WAIT_INFINITE
#define WAIT_INFINITE 0xFFFFFFFF
#endif

class _LxWaitObject;

// 对象等待工具，一次性工具，等待完毕后必须释放，不可再次使用
class _LxObjectWaiter : public std::enable_shared_from_this<_LxObjectWaiter>
{
public:
    pthread_mutexcond m_mutexcond;

    union
    {
        int firedEvent; // WFSO
        int eventsLeft; // WFMO
    } m_status;

    bool m_bWaitAll;	

    std::atomic<bool> m_bWaiting;

public:
    _LxObjectWaiter();
    ~_LxObjectWaiter();

    // 对于自动类型的等待对象（Event，Semaphore），只会触发一个等待

	/**
	 * 判断是否处于等待状态，
	 * @return 如果当前对象处于等待状态返回true，否则返回 false
	 *
	 * 本函数用于检查当前对象是否被标记为等待状态这通常用于同步操作，
	 * 以确定对象是否已经满足某些条件，从而可以继续执行操作
	 * * 本方法未进锁，仅靠原子操作访问等待状态
	 */
	bool IsWaiting() { return m_bWaiting.load(std::memory_order_relaxed); }

	/**
	 * 当信号触发时调用的函数
	 *
	 * @param nIndex 触发信号的索引，用于标识特定的信号
	 * @param bManual 指示信号是否是手动类型。如果为true，则表示信号是手动类型的；否则为false
	 * @return 返回一个布尔值，只有当前等待在触发前已经结束，且触发信号为自动类型时，才会返回false
	 * 
	 * 注意：本函数自身负责进锁
	 */
	bool OnSignaled(int nIndex, bool bManual);

	/**
	 * 等待多个或单个同步对象中的一个变为有信号状态。
	 *
	 * @param bWaitAll 是否等待所有对象都变为有信号状态。如果设置为true，函数将等待所有对象变为有信号状态；
	 *                 如果设置为false，函数将在任何一个对象变为有信号状态时返回。
	 * @param dwMilliseconds 等待时间的上限，以毫秒为单位。如果设置为INFINITE，将无限期等待。
	 * @param pWaitObjects 指向一个_LxWaitObject类型的数组，包含要等待的同步对象。
	 * @param count 数组中同步对象的数量，默认为1。如果bWaitAll设置为true，应确保所有对象都已初始化。
	 *
	 * @return 返回等待操作的结果。如果函数成功，返回值指示哪个对象变为有信号状态；
	 *         如果等待超时或发生错误，返回特定的错误代码。
	 * 
	 * 注意：本函数自身负责进锁
	 */
	int Wait(bool bWaitAll, unsigned int dwMilliseconds, _LxWaitObject *pWaitObjects, int count = 1);

public:
	// 无锁触发，返回值表示：是否结束等待
	// 由Wait和_LxWaitObject的PreWait调用
	/**
	 * UnlockedSignalOnce函数用于在未锁定的情况下发送一个信号。
	 * 此函数的目的是在某个特定条件下只发送一次信号，确保信号的唯一性和及时性。
	 *
	 * @param nIndex 信号的索引，用于标识特定的信号或操作。这个参数表明了在哪个位置或针对哪个项目发送信号。
	 * @return 返回一个布尔值，表示信号是否成功发送。如果发送成功，返回true；如果发送失败，返回false。
	 *
	 * 注意：调用此函数时需要确保调用者已经对对象进行了锁定，并且确保信号发送的条件已经满足。
	 */
	bool UnlockedSignalOnce(int nIndex);
};

// 正在等待该对象的Waiter的信息，包括该对象在Waiter中的等待索引
struct _SLxWaiter_Info
{
    std::shared_ptr<_LxObjectWaiter> pJWaiter;
    int nWaitIndex;	// 等待对象在Waiter中的索引
	_SLxWaiter_Info(std::shared_ptr<_LxObjectWaiter> &prJWaiter, int nIndex)
		: pJWaiter(prJWaiter), nWaitIndex(nIndex) {}
};

// 可以被Waiter等待的对象基类
class _LxWaitObject
{
public:
    pthread_mutex_t m_mutex;
    std::deque<_SLxWaiter_Info> m_waiters;

public:
    _LxWaitObject();
    virtual ~_LxWaitObject();

	/**
	 * 纯虚函数IsSignaled用于检查当前对象的状态是否为"已触发"。
	 *
	 * 此函数没有参数。
	 *
	 * 返回值:
	 *   - 如果对象的状态为"已触发"，则返回true。
	 *   - 如果对象的状态未"已触发"，则返回false。
	 *
	 * 注释:
	 *   - 此函数是一个纯虚函数，意味着它没有提供任何实现，子类必须重写此函数以提供具体实现。
	 *   - "已触发"状态的具体含义取决于特定的上下文或应用领域，例如，在同步原语中，这可能表示一个事件或条件已经被触发。
	 */
	virtual bool IsSignaled() = 0;
	/**
	 * 纯虚函数Signal用于在特定事件发生时发出信号。
	 * 此函数没有参数，也不返回任何值。
	 * 作用：提供一个接口，用于通知或触发其他部分的代码。
	 * 注意：这个函数是一个纯虚函数，意味着它没有提供实现，并且任何继承此类的子类都必须提供自己的实现。
	 */
	virtual void Signal() = 0;
	/**
	 * PreWait方法用于在等待操作前进行预处理。
	 * 该方法主要用于处理对象等待者在进入等待状态前需要完成的一些准备工作。
	 * 例如，它可以用于确保等待者在等待期间不会被非法访问或修改。
	 *
	 * @param prJWaiter 一个智能指针，指向_LxObjectWaiter类型的等待者对象。
	 *                  这个等待者对象在等待期间会被管理。
	 * @param nWaitIdx  等待者的索引，用于标识等待队列中的位置。
	 *                  这个索引帮助确定等待者的顺序或位置。
	 *
	 * @return 返回一个布尔值，表示预处理是否成功。
	 *         如果返回true，则表示预处理成功，可以继续进行等待操作；
	 *         如果返回false，则表示预处理失败，。
	 */
	virtual bool PreWait(std::shared_ptr<_LxObjectWaiter> &prJWaiter, int nWaitIdx);
	virtual void PostWait(_LxObjectWaiter *pWaiter);

protected:
	/**
	 *	达成一次经过等待的结果
	 *	实现在自动类型的对象（自动Event，Semaphore）在经过wait后状态的改变
	 *  函数不进锁，调用者负责线程同步
	 */
	virtual void OnBeWaited() {}

protected:
	void ClearExpireWaiters();
};

// 事件对象，可等待，可手动重置也可自动重置
class _LxEventObj : public _LxWaitObject
{
public:
    std::atomic<bool> m_bSignel;
    bool m_bAutoReset;

public:
    _LxEventObj(bool bManualReset = false, bool bInitialSignel = false);
	~_LxEventObj();

    virtual bool IsSignaled();
    virtual void Signal();
	virtual bool PreWait(std::shared_ptr<_LxObjectWaiter> &prJWaiter, int nWaitIdx);

protected:
	virtual void OnBeWaited();
};

// 信号量对象，可等待，可手动重置也可自动重置
class _LxSemaphoreObj : public _LxWaitObject
{
public:
	std::atomic<int> m_nValue;
	int m_nMaxValue;

public:
	_LxSemaphoreObj(int nInitial, int nMax = 0);
	~_LxSemaphoreObj();

	// nInitial: 初始值，nMax: 最大值，为0时等于nInitial
	virtual bool IsSignaled(); 
	virtual void Signal();

protected:
	virtual void OnBeWaited();
};